const getChildren = (list: any[], node: any, config: any) => {
  const { idKey, pidKey, childrenKey } = config
  const childrenList: any[] = []
  const nodeId = node[idKey]
  const treeList = list.map(item => ({ ...item, [childrenKey]: [] }))
  treeList.forEach(item => {
    const itemPid = item[pidKey]
    if (nodeId === itemPid) childrenList.push(item)
  })
  childrenList.forEach(child => {
    const item = child
    child[childrenKey] = getChildren(list, item, config)
  })
  return childrenList
}

/**
 * 将数组转为 tree 结构
 * @example
 * const list = [
 *  { id: '1', pid: null, other: '根节点' },
 *  { id: '2', pid: '1', other: '二级节点' },
 *  { id: '3', pid: '2', other: '三级节点' },
 *  { id: '4', pid: '2', other: '三级节点' },
 *  { id: '5', pid: null, other: '根节点' }
 * ]
 * list2Tree(list, {
 *  idKey: 'id',
 *  pidKey: 'pid',
 *  childrenKey: 'children'
 * })
 */
const list2Tree = <
  Item extends { [prop in IdKey | PidKey]: string | number },
  List extends Item[],
  PidKey extends keyof List[0],
  IdKey extends keyof List[0],
  ChildrenKey extends string
>(
  /** 需要被转换成 tree 结构的数组 */
  list: List,
  config: {
    /** 节点的唯一 id 的 key 值 */
    idKey: IdKey
    /** 节点的父节点的 id 的 key 值 */
    pidKey: PidKey
    /** 生成的子节点的 key 值 */
    childrenKey: ChildrenKey
    /** 根节点的父节点 */
    pid?: string | number
  }
) => {
  const { pidKey, childrenKey } = config
  type Node = List[0] & { [prop in typeof childrenKey]: Node[] }
  type Tree = Node[]

  const tree = list
    .filter(item => {
      const pid = item[pidKey]
      const isRootNode = !pid && pid !== 0
      if (isRootNode) return true
      return pid === config.pid
    })
    .map(item => ({ ...item, [childrenKey]: getChildren(list, item, config) })) as Tree

  return tree
}

export default list2Tree
